package net.goutalk.glcs.module.form.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import net.goutalk.glcs.common.enums.MenuType;
import net.goutalk.glcs.common.enums.YesOrNoEnum;
import net.goutalk.glcs.common.exception.MyException;
import net.goutalk.glcs.common.model.generator.ComponentConfig;
import net.goutalk.glcs.module.form.dto.AddFormReleaseDto;
import net.goutalk.glcs.module.form.dto.UpdateFormReleaseDto;
import net.goutalk.glcs.module.form.entity.FormDesignConfig;
import net.goutalk.glcs.module.form.entity.FormRelease;
import net.goutalk.glcs.module.form.entity.FormTemplate;
import net.goutalk.glcs.module.form.entity.MenuConfig;
import net.goutalk.glcs.module.form.mapper.FormReleaseMapper;
import net.goutalk.glcs.module.form.service.IFormReleaseService;
import net.goutalk.glcs.module.form.service.IFormTemplateService;
import net.goutalk.glcs.module.generator.constant.ComponentTypeConstant;
import net.goutalk.glcs.module.generator.entity.ColumnConfig;
import net.goutalk.glcs.module.generator.entity.ListConfig;
import net.goutalk.glcs.module.generator.utils.GeneratorUtil;
import net.goutalk.glcs.module.system.entity.*;
import net.goutalk.glcs.module.system.service.*;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import net.goutalk.glcs.module.system.entity.*;
import net.goutalk.glcs.module.system.service.*;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 自定义表单 发布表 服务实现类
 * </p>
 *
 * @author tanyujie
 * @since 2022-05-09
 */
@Service
@AllArgsConstructor
public class FormReleaseServiceImpl extends MPJBaseServiceImpl<FormReleaseMapper, FormRelease> implements IFormReleaseService {

    private final FormReleaseMapper formReleaseMapper;

    private final IFormTemplateService formTemplateService;

    private final IMenuService menuService;

    private final IMenuButtonService buttonService;

    private final IMenuColumnService columnService;

    private final IMenuFormService formService;

    private final IAuthorizeService authorizeService;

    private final ObjectMapper objectMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addFormRelease(AddFormReleaseDto dto) {

        boolean exists = menuService.count(Wrappers.<Menu>lambdaQuery().eq(Menu::getCode, dto.getMenuConfig().getCode())) > 0;
        if (exists) {
            throw new MyException("菜单编码已存在");
        }

        long releaseId = IdUtil.getSnowflakeNextId();

        Long formId = dto.getFormId();
        Long menuId = IdUtil.getSnowflakeNextId();
        insertMenuConfig(dto.getMenuConfig(), dto.getListConfig(), releaseId, formId, menuId);

        FormRelease formRelease = new FormRelease();
        formRelease.setId(releaseId);
        formRelease.setFormId(formId);
        formRelease.setMenuId(menuId);
        formRelease.setSortCode(dto.getMenuConfig().getSortCode());
        formRelease.setRemark(dto.getMenuConfig().getRemark());
        formRelease.setConfigJson(JSONUtil.toJsonStr(dto));

        return formReleaseMapper.insert(formRelease) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateFormRelease(UpdateFormReleaseDto dto) {

        Long menuId = dto.getMenuId();
        boolean exists = menuService.count(Wrappers.<Menu>lambdaQuery()
                .eq(Menu::getCode, dto.getMenuConfig().getCode())
                .ne(Menu::getId, menuId)) > 0;

        if (exists) {
            throw new MyException("菜单编码已存在");
        }
        // 删除原有数据
        buttonService.remove(Wrappers.<MenuButton>lambdaQuery().eq(MenuButton::getMenuId, menuId));
        columnService.remove(Wrappers.<MenuColumn>lambdaQuery().eq(MenuColumn::getMenuId, menuId));
        formService.remove(Wrappers.<MenuForm>lambdaQuery().eq(MenuForm::getMenuId, menuId));
        // 清除功能权限
        authorizeService.remove(Wrappers.<Authorize>query().lambda().eq(Authorize::getObjectId, menuId));

        insertMenuConfig(dto.getMenuConfig(), dto.getListConfig(), dto.getId(), dto.getFormId(), menuId);

        FormRelease formRelease = new FormRelease();
        formRelease.setId(dto.getId());
        formRelease.setFormId(dto.getFormId());
        formRelease.setMenuId(menuId);
        formRelease.setSortCode(dto.getMenuConfig().getSortCode());
        formRelease.setRemark(dto.getMenuConfig().getRemark());
        formRelease.setConfigJson(JSONUtil.toJsonStr(dto));

        return formReleaseMapper.updateById(formRelease) > 0;
    }


    /**
     * 默认插入菜单
     */
    @SneakyThrows
    private Long insertMenuConfig(MenuConfig menuConfig, ListConfig listConfig, Long releaseId, Long formId, Long menuId) {
        FormTemplate formTemplate = formTemplateService.getById(formId);
        FormDesignConfig formConfig = objectMapper.readValue(formTemplate.getFormJson(), FormDesignConfig.class);

        Menu menu = BeanUtil.toBean(menuConfig, Menu.class);
        menu.setId(menuId);
        menu.setName(menuConfig.getName() + RandomUtil.randomNumbers(4));
        menu.setTitle(menuConfig.getName());
        menu.setMenuType(MenuType.FUNCTION.getCode());
        menu.setDisplay(YesOrNoEnum.YES.getCode());
        menu.setAllowDelete(YesOrNoEnum.YES.getCode());
        menu.setAllowModify(YesOrNoEnum.YES.getCode());
        menu.setOutLink(YesOrNoEnum.NO.getCode());
        menu.setKeepAlive(YesOrNoEnum.NO.getCode());
        menu.setSortCode(menuConfig.getSortCode());
        menu.setFormId(formId);
        menu.setParentId(StrUtil.isBlank(menuConfig.getParentId()) ? 0L : Long.parseLong(menuConfig.getParentId()));

        menu.setComponentType(YesOrNoEnum.YES.getCode());
        //固定路径  与前端必须匹配
        menu.setPath("/custom-form/" + Convert.toStr(releaseId));
        menu.setComponent("/form/template/index");

        //新增菜单
        menuService.saveOrUpdate(menu);

        List<MenuButton> btnList = new ArrayList<>();
        listConfig.getButtonConfigs().forEach(buttonConfig -> {
            if (BooleanUtils.isTrue(buttonConfig.getIsUse())) {
                MenuButton menuButton = new MenuButton();
                menuButton.setMenuId(menu.getId());
                menuButton.setName(buttonConfig.getName());
                menuButton.setCode(menu.getCode() + StringPool.COLON + buttonConfig.getCode());
                menuButton.setIcon(buttonConfig.getIcon());
                btnList.add(menuButton);
            }
        });

        List<MenuColumn> colList = new ArrayList<>();
        for (ColumnConfig columnConfig : listConfig.getColumnConfigs()) {
            MenuColumn menuColumn = new MenuColumn();
            menuColumn.setMenuId(menu.getId());
            menuColumn.setName(columnConfig.getLabel());
            menuColumn.setCode(columnConfig.getColumnName());
            colList.add(menuColumn);
        }
        List<ComponentConfig> componentConfigList = GeneratorUtil.getFormComponentListWithoutLayout(formConfig.getFormJson().getList());
        List<MenuForm> formList = new ArrayList<>();
        for (ComponentConfig componentConfig : componentConfigList) {
            String type = componentConfig.getType();
            if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.SUB_FORM) || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.ONE_FOR_ONE_FORM)) {
                long id = IdUtil.getSnowflakeNextId();
                MenuForm menuForm = new MenuForm();
                menuForm.setId(id);
                menuForm.setMenuId(menu.getId());
                menuForm.setCode(componentConfig.getBindTable());
                menuForm.setName(componentConfig.getLabel());
                formList.add(menuForm);
                for (ComponentConfig subConfig : componentConfig.getChildren()) {
                    formList.add(buildMenuForm(id, menuId, subConfig));
                }
            } else {
                formList.add(buildMenuForm(0L, menuId, componentConfig));
            }
        }
        buttonService.saveBatch(btnList);
        columnService.saveBatch(colList);
        formService.saveBatch(formList);
        return menu.getId();
    }

    private MenuForm buildMenuForm(Long parentId, Long menuId, ComponentConfig componentConfig) {
        String field = null;
        String type = componentConfig.getType();
        if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.DATE_RANGE)
                || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.TIME_RANGE)) {
            field = componentConfig.getBindStartTime() + StringPool.COMMA + componentConfig.getBindEndTime();
        } else {
            field = StrUtil.isEmpty(componentConfig.getBindField()) ? componentConfig.getKey() : componentConfig.getBindField();
        }
        Boolean isRequired = MapUtils.getBoolean(componentConfig.getOptions(), "required", Boolean.FALSE);
        MenuForm subMenuForm = new MenuForm();
        subMenuForm.setParentId(parentId);
        subMenuForm.setMenuId(menuId);
        subMenuForm.setCode(field);
        subMenuForm.setName(componentConfig.getLabel());
        subMenuForm.setIsRequired(isRequired ? YesOrNoEnum.YES.getCode() : YesOrNoEnum.NO.getCode());
        return subMenuForm;
    }
}
